package system

import (
	"go.uber.org/zap"
	"strings"
	"sync"
	"time"

	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/util"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"server/global"
	sysModel "server/model/system"
)

type CasbinService struct {
}

var CasbinServiceApp = new(CasbinService)

//@author: [piexlmax](https://github.com/piexlmax)
//@function: Casbin
//@description: 持久化到数据库  引入自定义规则
//@return: *casbin.Enforcer

var (
	syncedEnforcer *casbin.SyncedEnforcer
	once           sync.Once
)

func (s *CasbinService) Casbin() *casbin.SyncedEnforcer {
	var err error
	once.Do(func() {
		a, _ := gormadapter.NewAdapterByDBWithCustomTable(global.GvaDb, &sysModel.SysCasbinRule{}, "sys_casbin_rule")
		syncedEnforcer, _ = casbin.NewSyncedEnforcer(global.GvaConfig.Casbin.ModelPath, a)
		syncedEnforcer.AddFunction("ParamsMatch", s.ParamsMatchFunc)
		//是否开启日志
		syncedEnforcer.EnableLog(false)
		//加载策略
		err = syncedEnforcer.LoadPolicy()
		if err != nil {
			global.GvaLog.Error("从数据库加载策略失败", zap.Any("err", err))
		}
	})
	// 定时同步策略
	if global.GvaConfig.Casbin.IntervalTime > 0 {
		syncedEnforcer.StartAutoLoadPolicy(time.Second * time.Duration(global.GvaConfig.Casbin.IntervalTime))
	}
	return syncedEnforcer
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: ParamsMatch
//@description: 自定义规则函数
//@param: fullNameKey1 string, key2 string
//@return: bool

func (s *CasbinService) ParamsMatch(fullNameKey1 string, key2 string) bool {
	key1 := strings.Split(fullNameKey1, "?")[0]
	// 剥离路径后再使用casbin的keyMatch2
	return util.KeyMatch2(key1, key2)
}

//@author: [piexlmax](https://github.com/piexlmax)
//@function: ParamsMatchFunc
//@description: 自定义规则函数
//@param: args ...interface{}
//@return: interface{}, error

func (s *CasbinService) ParamsMatchFunc(args ...interface{}) (interface{}, error) {
	name1 := args[0].(string)
	name2 := args[1].(string)

	return s.ParamsMatch(name1, name2), nil
}
